package com.gt.gcm;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Map.Entry;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.google.android.gcm.GCMRegistrar;

public class GtServerUtilities {

	private static final String TAG = "GtServerUtilities";
	private static final int MAX_ATTEMPTS = 5;
	private static final int BACKOFF_MILLI_SECONDS = 2000;
	private static final Random random = new Random();
	
	private static final int TIMEOUT_CONNECT=10000;
	private static final int TIMEOUT_READ=30000;

	private static final String PARAM_UID="uid";
	private static final String PARAM_USER_TOKEN="userToken";
	private static final String PARAM_CLIENT_TYPE="clientType";
	private static final String PARAM_LANGUAGE="language";
	
	
	//{tags
	private static final String TAG_STATUS_BEGIN="<status>";
	private static final String TAG_STATUS_END="</status>";
	//}
	
	
	public static String getIMEI(Context context){
		TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
		return telephonyManager.getDeviceId();
	}
	
	public static String getLocalMacAddress(Context context) { 

		WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 
		WifiInfo info = wifi.getConnectionInfo(); 
		return info.getMacAddress(); 
	} 
	
	public static String toMd5(byte[] bytes) {
		try {
			MessageDigest algorithm = MessageDigest.getInstance("MD5");
			algorithm.reset();
			algorithm.update(bytes);
			return toHexString(algorithm.digest(), "");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
	
	public static String toHexString(byte[] bytes, String separator) {
		StringBuilder hexString = new StringBuilder();
		for (byte b : bytes) {
			hexString.append(Integer.toHexString(0xFF & b)).append(separator);
		}
		return hexString.toString();
	}
	
	//20120806, Youth
	public static boolean registerGtHkServer(final Context context, final String regId,String language) {
		return registerGtHkServer(context, regId, language, null);
	}
	
    public static boolean registerGtHkServer(final Context context, final String regId,String language,ResultChecker resultChecker) {
        Log.i(TAG, "registerGtHkServer>>>regId=" + regId );
        //http://[domain] /api/addNUpdateUser.do
        String serverUrl = GCMManager.getServerUrlRegister();
        Map<String, String> params = new HashMap<String, String>();
        
        String  uuid = getIMEI(context);
        Log.i(TAG, "registerGtHkServer>>>isNeedWifiMac =" +GCMManager.isNeedWifiMac());
        
        if(GCMManager.isNeedWifiMac() && uuid == null){
        	uuid = toMd5(getLocalMacAddress(context).getBytes());
        }
        
        
        if(GCMManager.isNeedWifiMac()){
        	params.put("uuid", uuid);
        }else{
        	params.put(PARAM_UID, uuid);
        }
        
        Log.i(TAG, "registerGtHkServer>>>uuid =" +uuid);
        
        
        params.put(PARAM_USER_TOKEN, regId);
        params.put(PARAM_CLIENT_TYPE, "Android");
        params.put(PARAM_LANGUAGE, language);
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);

        for (int i = 1; i <= MAX_ATTEMPTS; i++) {
            Log.d(TAG, "registerGtHkServer>>>Attempt #" + i + " to register");
            String returnText=null;
            try {
                returnText=postWithResult(serverUrl, params);
                if(returnText==null){
                	Log.e(TAG, "registerGtHkServer>>>returnText is null");
                	continue;
                }
                if(resultChecker!=null){
                	if(!resultChecker.checkResult(returnText)){
                		Log.e(TAG, "registerGtHkServer>>>resultChecker>>>returnText="+returnText);
                		return false;
                	}
                }
                else{
                	if(!isSuccessByYouthStyle(returnText)){
                    	Log.e(TAG, "registerGtHkServer>>>returnText="+returnText);
                    	return false;
                    }
                }
                
                GCMRegistrar.setRegisteredOnServer(context, true);
                return true;
            } catch (Exception e) {

                Log.e(TAG, "Failed to register on attempt " + i, e);
                Log.e(TAG, "registerGtHkServer>>>exception>>>returnText="+returnText);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(TAG, "Sleeping for " + backoff + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(TAG, "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return false;
                }
                // increase backoff exponentially
                backoff *= 2;
            }
        }
        return false;
    }
    
    private static boolean isSuccessByYouthStyle(String text){
    	if(text==null){
    		return false;
    	}
    	/*
    	 * Youth
    	 * <?xml version="1.0" encoding="UTF-8"?>
	  	 *		<youth>
		 *			<status>0</status>
		 *		</youth>
    	 */
    	int beginIndex=text.indexOf(TAG_STATUS_BEGIN)+TAG_STATUS_BEGIN.length();
    	int endIndex=text.indexOf(TAG_STATUS_END);
    	String code=text.substring(beginIndex, endIndex);
    	Log.i(TAG, "isSuccessByYouthStyle>>>code="+code);
    	if(code.trim().equals("0")){
    		return true;
    	}
    	return false;
    }
    
    private static String postWithResult(String endpoint, Map<String, String> params)
            throws Exception {
    	if(endpoint==null){
    		return null;
    	}
        URL url;
        try {
            url = new URL(endpoint);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("invalid url: " + endpoint);
        }
        StringBuilder bodyBuilder = new StringBuilder();
        Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
        // constructs the POST body using the parameters
        while (iterator.hasNext()) {
            Entry<String, String> param = iterator.next();
            bodyBuilder.append(param.getKey()).append('=')
                    .append(param.getValue());
            if (iterator.hasNext()) {
                bodyBuilder.append('&');
            }
        }
        String body = bodyBuilder.toString();
        Log.v(TAG, "Posting '" + body + "' to " + url);
        byte[] bytes = body.getBytes();
        HttpURLConnection conn = null;
        OutputStream out=null;
        InputStream inputStream=null;
        ByteArrayOutputStream baos=null;
        try {
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(GCMManager.getTimeConnectTimeout());
            conn.setReadTimeout(GCMManager.getTimeReadTimeout());
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setConnectTimeout(TIMEOUT_CONNECT);
            conn.setReadTimeout(TIMEOUT_READ);
            conn.setFixedLengthStreamingMode(bytes.length);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded;charset=UTF-8");
            // post the request
            out = conn.getOutputStream();
            out.write(bytes);
            out.close();
            // handle the response
            int status = conn.getResponseCode();
            if (status != 200) {
              throw new IOException("Post failed with error code " + status);
            }
            inputStream=conn.getInputStream();
            baos=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int bytesCount=0;
            while((bytesCount=inputStream.read(buffer))!=-1){
            	baos.write(buffer, 0, bytesCount);
            }
            baos.flush();
            String result=baos.toString("UTF-8");
            return result;
        } finally {
        	if(out!=null){
        		try{
        			out.close();
        		}
        		catch(Exception e){
        			e.printStackTrace();
        		}
        	}
        	if(inputStream!=null){
        		try{
        			inputStream.close();
        		}
        		catch(Exception e){
        			e.printStackTrace();
        		}
        	}
        	if(baos!=null){
        		try{
        			baos.close();
        		}
        		catch(Exception e){
        			e.printStackTrace();
        		}
        	}
            if (conn != null) {
                try{
                	conn.disconnect();
                }
                catch(Exception e){
                	e.printStackTrace();
                }
            }
        }
      }
    
   
}
